package com.retrozelda.nyanimals;

import java.util.LinkedList;

import android.graphics.RectF;
import android.opengl.GLES20;
import android.opengl.Matrix;

public class CBitmapFont extends CRectangle
{
	private class CText
	{
		public String	text;
		public int		posX;
		public int		posY;

		public CText(String szText, int posX, int posY)
		{
			this.text = szText;
			this.posX = posX;
			this.posY = posY;
		}
	};

	int					m_charWidth;
	int					m_charHeight;
	int					m_startingChar;

	RectF[]				m_CharMap;
	LinkedList<CText>	m_DrawText;

	@Override
	public Object clone()
	{
		CBitmapFont ret = (CBitmapFont)super.clone();

		ret.m_charWidth = m_charWidth;
		ret.m_charHeight = m_charHeight;
		ret.m_startingChar = m_startingChar;

		ret.m_CharMap = m_CharMap.clone();
		ret.m_DrawText = new LinkedList<CText>(m_DrawText);

		return ret;
	}

	@Override
	public void Init(NyanimalGLSurfaceView game)
	{
		super.Init(game);
		m_Texture = CTextureManager.GetInstance().LoadTexture(R.drawable.times_news_roman, game);

		m_startingChar = (int)'!';
		m_charWidth = 32;
		m_charHeight = 32;

		SetSize(m_charWidth, m_charHeight);

		// create the rect array
		int numWidth = m_Texture.GetWidth() / m_charWidth;
		int numHeight = (m_Texture.GetHeight() / m_charHeight);
		int numBlock = numWidth * numHeight;
		m_CharMap = new RectF[numBlock];
		m_DrawText = new LinkedList<CBitmapFont.CText>();

		for(int charIndex = 0; charIndex < numBlock; ++charIndex)
		{
			int col = charIndex % numWidth;
			int row = charIndex / numWidth;

			// build the rect
			RectF charRect = new RectF();
			charRect.top = row * m_charHeight;
			charRect.bottom = charRect.top + m_charHeight;
			charRect.right = col * m_charWidth;
			charRect.left = charRect.right + m_charWidth;

			// get into texture space
			charRect.top /= m_Texture.GetHeight();
			charRect.bottom /= m_Texture.GetHeight();
			charRect.left /=  m_Texture.GetWidth();
			charRect.right /=  m_Texture.GetWidth();

			// insert it
			m_CharMap[charIndex] = charRect;
		}
	}

	@Override
	public void Update(float deltaTime)
	{

	}

	public void DrawText(String szText, int posX, int posY)
	{
		CText text = new CText(szText, posX, posY);
		m_DrawText.addLast(text);
	}

	@Override
	public void Draw(CArgumentGroup arg)
	{
		// activate the stuff
		GLES20.glUseProgram(m_ShaderProgram);
		GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
		GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, m_Texture.GetTextureID());

		// set the texture
		GLES20.glVertexAttribPointer(m_TextureHandle, 2, GLES20.GL_FLOAT,
				false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, m_TriangleVertices);
		GLES20.glEnableVertexAttribArray(m_TextureHandle);

		// set the verts
		m_TriangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
		GLES20.glVertexAttribPointer(m_PositionHandle, 3, GLES20.GL_FLOAT,
				false, TRIANGLE_VERTICES_DATA_STRIDE_BYTES, m_TriangleVertices);

		int textSize = m_DrawText.size();
		for(int textIndex = 0; textIndex < textSize; ++textIndex)
		{
			CText text = m_DrawText.get(textIndex);
			int posX = text.posX + (int)(m_scale[0] / 2.0f);
			int posY = text.posY + (int)(m_scale[1] / 2.0f);

			int stringLength = text.text.length();
			for(int stringIndex = 0; stringIndex < stringLength; ++stringIndex)
			{
				char curChar = text.text.charAt(stringIndex);

				// ensure valid indicies
				if((int)curChar - m_startingChar >= 0)
				{
					FocusChar((int)curChar);

					// freshen the model matrix
					Matrix.setIdentityM(m_MMatrix, 0);

					// set the position
					Matrix.translateM(m_MMatrix, 0, posX, posY, 0.0f);

					// set any rotations

					// set any scales
					Matrix.scaleM(m_MMatrix, 0, m_scale[0], m_scale[1], 1.0f);
					// //////////////////////////////////////

					// calculate the MVP
					Matrix.multiplyMM(m_MVPMatrix, 0,
							arg.GameClass.GetViewProjection(), 0, m_MMatrix, 0);

					// set the UVs
					m_TriangleVertices
							.position(TRIANGLE_VERTICES_DATA_UV_OFFSET);
					GLES20.glEnableVertexAttribArray(m_PositionHandle);

					// set the MVP
					GLES20.glUniformMatrix4fv(m_MVPMatrixHandle, 1, false,
							m_MVPMatrix, 0);

					// Draw the char
					GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
				}
				posX += m_charWidth;
			}
		}
		m_DrawText.clear(); 
	}

	RectF m_focusCharRect;
	private void FocusChar(int charIndex)
	{
		// get the UV rect
		m_focusCharRect = m_CharMap[charIndex - m_startingChar];

		// put the rect where it belongs in the vertices
		// top right
		m_TriangleVerticesData[3] = m_focusCharRect.right;
		m_TriangleVerticesData[4] = m_focusCharRect.top;

		// bottom right
		m_TriangleVerticesData[8] = m_focusCharRect.right;
		m_TriangleVerticesData[9] = m_focusCharRect.bottom;

		// top left
		m_TriangleVerticesData[13] = m_focusCharRect.left;
		m_TriangleVerticesData[14] = m_focusCharRect.top;

		// bottom left
		m_TriangleVerticesData[18] = m_focusCharRect.left;
		m_TriangleVerticesData[19] = m_focusCharRect.bottom;

		// save
		m_TriangleVertices.position(0);
		m_TriangleVertices.put(m_TriangleVerticesData).position(0);
	}
}
